package genetica.cromosomas;

import java.util.ArrayList;
import java.util.Random;

import genetica.cromosomas.evaluadores.EvaluadorPG;
import genetica.cromosomas.fenotipos.Fenotipo;
import genetica.cromosomas.fenotipos.FenotipoPG;
import genetica.cromosomas.fenotipos.fenotipoPG.BS;
import genetica.cromosomas.fenotipos.fenotipoPG.CP;
import genetica.cromosomas.fenotipos.fenotipoPG.DU;
import genetica.cromosomas.fenotipos.fenotipoPG.EQ;
import genetica.cromosomas.fenotipos.fenotipoPG.Funcion;
import genetica.cromosomas.fenotipos.fenotipoPG.MM;
import genetica.cromosomas.fenotipos.fenotipoPG.MP;
import genetica.cromosomas.fenotipos.fenotipoPG.NOT;
import genetica.cromosomas.fenotipos.fenotipoPG.Nodo;
import genetica.cromosomas.fenotipos.fenotipoPG.SN;
import genetica.cromosomas.fenotipos.fenotipoPG.TreePG;
import genetica.cromosomas.genes.Gen;

public class CromosomaPG extends Cromosoma{

	protected FenotipoPG genotipo;
	public CromosomaPG(){
		super();
		Cromosoma.evaluador = new EvaluadorPG();
		this.fenotipo = new ArrayList<Fenotipo>();
		this.genotipo = new FenotipoPG();
		// TODO inicializar
		this.genotipo.setArbol(inicializarNodo(null,0));
		this.fenotipo.add(this.genotipo);
		
	}
	// 0-2 Terminales
	// 3-7 Funciones
	//  - 3-4 Reciben terminales devuelven aridad 1
	//  - 5   Reciben funcion o terminal, aridad 1
	//  - 6-7 Reciben funcion o terminal, aridad 2
	//  
	public static Nodo[] nodos = {
		new BS(), // 0
		new CP(), // 1
		new SN(), // 2
		new MP(), // 3
		new MM(), // 4 
		new NOT(),// 5
		new DU(), // 6
		new EQ(), // 7
	};
	static Random r = new Random();
	public static TreePG inicializarNodo(TreePG padre, int profundidad){

		if ((padre == null) || (profundidad < TreePG.profundidadMaxima) && 
				((padre.getNodo() instanceof NOT) || 
				(padre.getNodo() instanceof DU) || 
				(padre.getNodo() instanceof EQ))) { 
			int sig = r.nextInt(8);
			TreePG hijo = new TreePG(nodos[sig]);
			hijo.setNivel(profundidad);
			if (sig >= 3)
				hijo.addHijo(inicializarNodo(hijo, profundidad+1));
			if (sig >= 6)
				hijo.addHijo(inicializarNodo(hijo, profundidad+1));
			return hijo;
		}
		if ((padre.getNodo() instanceof MP) || (padre.getNodo() instanceof MM) || padre.getNivel() >= TreePG.profundidadMaxima-2){
			int sig = r.nextInt(3);
			TreePG hijo = new TreePG(nodos[sig]);
			hijo.setNivel(profundidad);
			return hijo;
		}
		throw new Error("Error al incializar, nodo terminal donde no debería");

	}
	
	public CromosomaPG(CromosomaPG other){
		super();
		this.aptitud = other.aptitud;
		this.punt_acumu = other.punt_acumu;
		this.puntuacion = other.puntuacion;
		this.genotipo = other.genotipo.clone();
		this.fenotipo = new ArrayList<Fenotipo>();
		this.fenotipo.add(this.genotipo);
	}
	
	@Override
	public void calcularFenotipo() {
		this.fenotipo.clear();
		this.fenotipo.add(this.genotipo);
		// TODO Auto-generated method stub
		
	}

	@Override
	public Cromosoma clone() {
		Cromosoma nuevoCromosoma = new CromosomaPG(this);
		return nuevoCromosoma;
	}

	@Override
	public void codifica() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void decodifica() {
		// TODO Auto-generated method stub
		
	}

	public FenotipoPG getGenotipo(){
		return this.genotipo;
	}
	
	public void setGenotipo(FenotipoPG genotipo){
		this.genotipo = genotipo;
	}

	public String toString(){
		return this.fenotipo.toString();
	}

}
